package com.cindata

import com.jcraft.jsch.Channel
import com.jcraft.jsch.ChannelSftp
import com.jcraft.jsch.JSch
import com.jcraft.jsch.Session

import grails.transaction.Transactional

@Transactional
class SftpService
{

    def grailsApplication

    def uploadFile(InputStream inputStream, String fileName)
    {
        connect { ChannelSftp sftp -> sftp.put inputStream, fileName
        }
    }

    def downloadFile()
    {
        String fileName = grailsApplication.config.sftp.fileName
        connect({ ChannelSftp sftp ->
            File outputFile = File.createTempFile(fileName, '')
            outputFile?.newOutputStream() << sftp.get(fileName)
            outputFile

            InputStream it = null;
            OutputStream os = null;
            try
            {
                it = new FileInputStream(outputFile)
                String localPath = grailsApplication.config.sftp.localPath
                File localFile = new File(localPath + "/" + fileName)
                os = new FileOutputStream(localFile)
                //文件拷贝
                byte[] flush = new byte[1024]
                int len = 0
                Date beginDate = new Date();
                while (0 <= (len = it.read(flush)))
                {
                    os.write(flush, 0, len)
                }
                Date endDate = new Date();
                log.info("Copy file time consuming :" + (endDate.getTime() - beginDate.getTime()) / 1000 + " sec")
            }
            catch (Exception e)
            {
                e.printStackTrace()
                log.error(e)
            }
            finally
            {
                if (os != null)
                {
                    os.close()
                }

                if (it != null)
                {
                    it.close()
                }
                outputFile.delete()
            }
                }, false)
    }

    def removeFile() throws Throwable
    {
        String fileName = grailsApplication.config.sftp.fileName
        connect { ChannelSftp sftp -> sftp.rm fileName
        }
    }

    def renameFile(String oldPath, String newPath)
    {
        connect { ChannelSftp sftp -> sftp.rename oldPath, newPath
        }
    }

    def createDir(String dirName)
    {
        connect { ChannelSftp sftp -> sftp.mkdir dirName
        }
    }

    private def connect(Closure c, boolean disconnect = true)
    {
        Session session = null
        ChannelSftp sftp = null
        String server = grailsApplication.config.sftp.server
        String username = grailsApplication.config.sftp.username
        String password = grailsApplication.config.sftp.password
        String remoteDir = grailsApplication.config.sftp.remoteDir
        Integer port = grailsApplication.config.sftp.port.toInteger()
        String keyFilePath = grailsApplication.config.sftp.keyFilePath
        Boolean throwException = grailsApplication.config.sftp.throwException

        try
        {
            JSch jSch = new JSch()
            session = jSch.getSession username, server, port
            session.setConfig "StrictHostKeyChecking", "no"

            if (password)
            {
                session.password = password
            }
            else
            {
                File keyFile = new File(keyFilePath)
                jSch.addIdentity(keyFile?.absolutePath)
            }

            session.connect()
            Channel channel = session.openChannel "sftp"
            channel.connect()
            sftp = channel as ChannelSftp
            sftp.cd remoteDir
            c.call sftp
        }
        catch (Exception e)
        {
            e.printStackTrace()
            log.error(e)
            if (throwException)
            {
                throw e
            }
        }
        finally
        {
            if (disconnect)
            {
                sftp?.exit()
                session?.disconnect()
            }
        }
    }
}
